package com.nexgo.payment.util;

import android.os.Environment;
import android.text.TextUtils;

import com.nexgo.payment.App;
import com.nexgo.payment.constrant.PreferencesConstants;
import com.nexgo.payment.constrant.SysConstant;
import com.nexgo.payment.databases.DataSource;
import com.nexgo.payment.databases.PasswordInfo;
import com.nexgo.payment.databases.Repository;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;

import info.monitorenter.cpdetector.io.ASCIIDetector;
import info.monitorenter.cpdetector.io.CodepageDetectorProxy;
import info.monitorenter.cpdetector.io.JChardetFacade;
import info.monitorenter.cpdetector.io.ParsingDetector;
import info.monitorenter.cpdetector.io.UnicodeDetector;

/**
 * 1.从assets /导TempletPara.ini 参数文件导参数
 * 2.从TMU 导入TempletPara.ini 参数文件导参数
 * Created by wanghongyang on 2017/11/04.
 */
public class ParamFileManager {
    private Logger mLog = LoggerFactory.getLogger(ParamFileManager.class.getSimpleName());

    private  String tmpFileDir;  //PC下载临时参数文件的绝对目录
    private  String tmpFileName = "/para.ini"; //PC下载临时参数文件名
    private DataSource mRepository = Repository.getInstance();
    private HashMap<String, String> spKeyMap = new HashMap<>();
    private static ParamFileManager INSTANCE;

    public ParamFileManager(){
        String applicationId = App.sContext.getApplicationInfo().processName;
        tmpFileDir = "/";
        if(!TextUtils.isEmpty(applicationId)) {
            tmpFileDir += applicationId.replace(".", "");
        }
        initParamCode2Key();
    }

    public static ParamFileManager getInstance() {
        synchronized (ParamFileManager.class){
            if (INSTANCE == null){
                INSTANCE = new ParamFileManager();
            }
        }
        return INSTANCE;
    }

    /**
     * 初始化 参数编码与实际存储的key映射关系
     */
    private void initParamCode2Key(){
        //商户管理
        spKeyMap.put("01000001", PreferencesConstants.MERCHANT_ID);
        spKeyMap.put("01000002", PreferencesConstants.MERCHANT_NAME);
        spKeyMap.put("01000005", PreferencesConstants.TERMINAL_ID);
        //交易管理 传统类交易控制
        spKeyMap.put("01000023", PreferencesConstants.SALE_SWITCH);
        spKeyMap.put("01000025", PreferencesConstants.SALE_VOID_SWITCH);
        spKeyMap.put("01000026", PreferencesConstants.REFUND_SWITCH);
        spKeyMap.put("01000024", PreferencesConstants.QUERY_SWITCH);
        spKeyMap.put("01000022", PreferencesConstants.PRE_AUTH_SWITCH);
        spKeyMap.put("01000010", PreferencesConstants.PRE_AUTH_VOID_SWITCH);
        spKeyMap.put("01000012", PreferencesConstants.PRE_AUTH_COMPLETE_SWITCH);
        spKeyMap.put("01000013", PreferencesConstants.PRE_AUTH_COMPLETE_NOTIFY_SWITCH);
        spKeyMap.put("01000014", PreferencesConstants.PRE_AUTH_COMPLETE_VOID_SWITCH);
        //其它参数设置  是否输密
        spKeyMap.put("01000090", PreferencesConstants.VOID_NEED_PASSWORD);
        spKeyMap.put("01000075", PreferencesConstants.PRE_AUTH_VOID_NEED_PASSWORD);
        spKeyMap.put("01000076", PreferencesConstants.PRE_AUTH_COMPLETE_VOID_NEED_PASSWORD);
        spKeyMap.put("01000077", PreferencesConstants.PRE_AUTH_COMPLETE_NEED_PASSWORD);
        //交易刷卡控制
        spKeyMap.put("01000034", PreferencesConstants.TRANS_VOID_SWIPE_CARD);
        spKeyMap.put("01000035", PreferencesConstants.TRANS_AUTH_COM_VOID_SWIPE_CARD);
        //结算交易控制
        spKeyMap.put("01000030", PreferencesConstants.AUTO_LOGOUT_SWITCH);
        spKeyMap.put("01000060", PreferencesConstants.PROMPT_PRINT_DETAIL_SWITCH);
        //其它参数设置
        spKeyMap.put("01000041", PreferencesConstants.OFFLINE_TRANS_UPLOAD_TIMES);
        spKeyMap.put("01000009", PreferencesConstants.OFFLINE_TRANS_UPLOAD_NUMBER);
        spKeyMap.put("01000088", PreferencesConstants.REVERSAL_UPLOAD_TIMES);
        spKeyMap.put("01000033", PreferencesConstants.ALLOW_MANUAL_PAN);
        spKeyMap.put("01000040", PreferencesConstants.MAX_REFUND_AMOUNT);
        spKeyMap.put("01000131", PreferencesConstants.IS_NEED_CONFIRM_CARD_NO);
        //系统参数设置
        spKeyMap.put("01000082", PreferencesConstants.TRACE_NUMBER);
        spKeyMap.put("01000083", PreferencesConstants.BATCH_NUMBER);
        spKeyMap.put("01000130", PreferencesConstants.OPEN_VOICE_PROMPT);
        spKeyMap.put("01000078", PreferencesConstants.ORDER_NEED_ENGLISH);
        spKeyMap.put("01000007", PreferencesConstants.VOID_CLASS_NEED_PRINT_MINUS_SIGN);
        spKeyMap.put("01000042", PreferencesConstants.PRINT_TIMES);
        spKeyMap.put("01000052", PreferencesConstants.MAX_NUMBER_OF_TRANS);
        //非接参数控制
        spKeyMap.put("01000119", PreferencesConstants.RF_PRIORITY_ONLINE);
        spKeyMap.put("01000120", PreferencesConstants.PRIORITY_TO_USE_RF);
        spKeyMap.put("01000121", PreferencesConstants.QPS_SUPPORT_FREE_PASSWORD);
        spKeyMap.put("01000122", PreferencesConstants.QPS_LIMIT_OF_FREE_PASSWORD);
        spKeyMap.put("01000123", PreferencesConstants.QPS_SUPPORT_FREE_SIGNATURE);
        spKeyMap.put("01000124", PreferencesConstants.QPS_LIMIT_OF_FREE_SIGNATURE);
        spKeyMap.put("01000125", PreferencesConstants.QPS_SUPPORT_CARD_BIN_A);
        spKeyMap.put("01000126", PreferencesConstants.QPS_SUPPORT_CARD_BIN_B);
        spKeyMap.put("01000127", PreferencesConstants.QPS_SUPPORT_CARD_BIN_C);
        spKeyMap.put("01000128", PreferencesConstants.QPS_SUPPORT_CDCVM);
        spKeyMap.put("01000129", PreferencesConstants.EC_FREE_SIGNATURE);
        //网络参数设置
        spKeyMap.put("01000049", PreferencesConstants.TPDU);
        spKeyMap.put("01000062", PreferencesConstants.SERVER_IP);
        spKeyMap.put("01000063", PreferencesConstants.SERVER_PORT);
        spKeyMap.put("01000008", PreferencesConstants.COMMUNICATION_TIMEOUT);
        spKeyMap.put("01000095", PreferencesConstants.ENABLE_SSL);
        spKeyMap.put("01000106", PreferencesConstants.DNS_URL);
        //终端密钥管理
        spKeyMap.put("01000048", PreferencesConstants.MASTER_KEY_INDEX);
        spKeyMap.put("01000072", PreferencesConstants.MASTER_KEY_ALGORITHM);
        spKeyMap.put("01000117", PreferencesConstants.TRACK_ENCRYPTED);
        spKeyMap.put("01000118", PreferencesConstants.EMV_SUPPORT_SM2);
        //签购单打印
        spKeyMap.put("01000015", PreferencesConstants.PRINT_TITLE);
        spKeyMap.put("01000016", PreferencesConstants.PRINT_TITLE_SELECT);
        spKeyMap.put("01000017", PreferencesConstants.SERVICE_PHONE);
        //电子签名设置
        spKeyMap.put("01000110", PreferencesConstants.IS_SUPPORT_ELEC_SIGNATURE);
        spKeyMap.put("01000111", PreferencesConstants.IS_SHOW_CONFIRM_SIGNATURE);
        spKeyMap.put("01000112", PreferencesConstants.SIGNATURE_TIME_OUT);
        spKeyMap.put("01000113", PreferencesConstants.SIGNATURE_UPLOAD_TIMES);
        spKeyMap.put("01000114", PreferencesConstants.MAX_SIGNATURE_TIMES);
        spKeyMap.put("01000115", PreferencesConstants.IS_NEED_PHONE_NUMBER);
        spKeyMap.put("01000116", PreferencesConstants.IS_PRINT_SALES_SLIP);
        spKeyMap.put("01000132",PreferencesConstants.ACQUIRING_NUMBER);
        //wzp
        spKeyMap.put("01000134",PreferencesConstants.NEED_CHECK_BASE);
    }

    /**
     * tmu传送的参数编号与实际存储的key映射
     */
    private String paramCode2Key(String code){
        String spkey = "";
        for (Map.Entry<String, String> entry : spKeyMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            if(key.equals(code)){
                spkey = value;
                break;
            }
        }
        return  spkey;
    }

    private void  updateParam(String code, String value, boolean bOverSave){
        if(TextUtils.isEmpty(code) || TextUtils.isEmpty(value)){
            return;
        }
        //系统管理员密码 wzp
        if(code.equals("01000051")){
            PasswordInfo info = mRepository.getPasswordInfo();
            if(bOverSave || info == null) {
                info = new PasswordInfo();
                info.setManagePassword(EncryptUtils.encryptSHA256ToString(value));
                mRepository.setPasswordInfo(info);
            }else{
                if(TextUtils.isEmpty(info.getManagePassword())){
                    info.setManagePassword(EncryptUtils.encryptSHA256ToString(value));
                    mRepository.setPasswordInfo(info);
                }
            }
            return;
        }
        //主管密码 wzp
        if(code.equals("01000081")){
            PasswordInfo info = mRepository.getPasswordInfo();
            if(bOverSave || info == null) {
                info = new PasswordInfo();
                info.setAdminPassword(EncryptUtils.encryptSHA256ToString(value));
                mRepository.setPasswordInfo(info);
            }else{
                if(TextUtils.isEmpty(info.getAdminPassword())){
                    info.setAdminPassword(EncryptUtils.encryptSHA256ToString(value));
                    mRepository.setPasswordInfo(info);
                }
            }
            return;
        }
        //安全密码 wzp
        if(code.equals("01000080")){
            PasswordInfo info = mRepository.getPasswordInfo();
            if(bOverSave || info == null) {
                info = new PasswordInfo();
                info.setSecurityPassword(EncryptUtils.encryptSHA256ToString(value));
                mRepository.setPasswordInfo(info);
            }else{
                if(TextUtils.isEmpty(info.getSecurityPassword())){
                    info.setSecurityPassword(EncryptUtils.encryptSHA256ToString(value));
                    mRepository.setPasswordInfo(info);
                }
            }
            return;
        }
        String spkey = paramCode2Key(code);
        if(!TextUtils.isEmpty(spkey)) {
            if(bOverSave || (TextUtils.isEmpty(mRepository.getParamValue(spkey)))) {
                mRepository.setParamValue(spkey, value);
            }
        }
    }

    /**
     * 解析TempletPara.ini并导入参数
     */
    public void parseTemplateParam(){
        //2.解析assert/TempletPara.ini
        parseTemplateParamFromAssets();
        //3.检测并解析 SD/TempletPara.ini
        parseTemplateParamFromPC();
    }
    /**
     * 解析assets目录下 TempletPara.ini
     */
    private void parseTemplateParamFromAssets(){
        //保存数据到SP中
        if (!fileCopySP(SysConstant.TEMPLATE_PARA_INI,false)) {
            mLog.error("----文件数据保存到SP中失败-----");
            return ;
        }
    }

    /**
     * 解析PC下载的para.ini
     */
    private void parseTemplateParamFromPC(){
        String absoluteFilePath = getFilePath();
        String  absoluteFileName = absoluteFilePath + tmpFileName;
        //判断sd卡根目录  /storage/emulated/0/para.ini 参数文件是否存在
        if (!isFileExists(absoluteFileName)) {
            mLog.error("----参数文件不存在-----");
            return ;
        }
        mLog.debug("-----文件存在--------" + absoluteFileName);
        //判断是否为UTF-8模式
        if (!isCharUnicodeUTF(absoluteFileName)) {
            mLog.debug("----不是UTF-8模式-----");
            if (!change(absoluteFileName)) {
                mLog.error("---切换UTF-8失败-----");
                return ;
            }
            mLog.debug("---切换UTF-8成功-----");
        }

        //保存数据到SP中
        if (!fileCopySP(absoluteFileName,true)) {
            mLog.error("----文件数据保存到SP中失败-----");
            return ;
        }
        ToastUtils.showToast("参数导入成功");
        mLog.debug("---文件数据保存到SP中成功-----");

        //判断sd卡 删除参数文件和目录
        if (isFileExists(absoluteFileName)) {
            deleteFile(absoluteFileName);
        }
        if (isFileExists(absoluteFilePath)) {
            deleteFile(absoluteFilePath);
        }
    }

    /**
     * 获取SD卡跟目录
     *
     * @return
     */
    private String getSDPath() {
        File sdDir = null;
        boolean sdCardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);//判断sd卡是否存在
        if (sdCardExist) {
            sdDir = Environment.getExternalStorageDirectory();//获取跟目录
        }
        if (sdDir == null) {
            return null;
        }
        return sdDir.toString();
    }

    private String getFilePath() {
        return getSDPath() + tmpFileDir;
    }

    /**
     * 判断文件是否存在
     *
     * @return
     */
    private boolean isFileExists(String fileDir) {
        File f = new File(fileDir);
        return f.exists();
    }
    /**
     * 删除文件
     *
     * @return
     */
    private boolean deleteFile(String fileDir) {
        File f = new File(fileDir);
        return f.delete();
    }


    /**
     * 判断文件格式是否为UTF-8
     *
     * @return
     */
    private boolean isCharUnicodeUTF(String fileDir) {
        String charUnicode = getFileEncode(fileDir);
        if ("UTF-8".equalsIgnoreCase(charUnicode)) return true;
        return false;
    }

    /**
     * 把GB2312格式转换成UTF-8
     *
     * @param filepath
     * @return
     */
    private boolean change(String filepath) {
        try {
            BufferedReader buf = null;
            OutputStreamWriter pw = null;
            String str = null;
            String allstr = "";

            //用于输入换行符的字节码
            byte[] c = new byte[2];
            c[0] = 0x0d;
            c[1] = 0x0a;
            String t = new String(c);

            buf = new BufferedReader(new InputStreamReader(new FileInputStream(filepath), "GBK"));
            while ((str = buf.readLine()) != null) {
                allstr = allstr + str + t;
            }

            buf.close();

            pw = new OutputStreamWriter(new FileOutputStream(filepath), "UTF-8");
            pw.write(allstr);
            pw.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
    /**
     * String fileName   文件名称
     * boolean bOverSave  是否覆盖保存
     * 以行为单位读取文件，常用于读面向行的格式化文件
     */
    private boolean fileCopySP(String fileName,boolean bOverSave) {
        BufferedReader reader = null;
        try {
            if(bOverSave) {
                File file = new File(fileName);
                reader = new BufferedReader(new FileReader(file));
            }else{
                InputStreamReader inputStreamReader = new InputStreamReader(App.sContext.getAssets().open(fileName));
                reader = new BufferedReader(inputStreamReader);
            }
            String tempString = null;
            mLog.error("---------------start---------------------");
            // 一次读入一行，直到读入null为文件结束
            while ((tempString = reader.readLine()) != null) {
                // 显示行号
                if (tempString.trim().length() > 0) {
                    if (tempString.indexOf(",") > 0) {
                        String[] datas = tempString.split(",");
                        if (datas.length == 6) {
                            mLog.error("ini------" + datas[0] + " : " + datas[5]);
                            updateParam(datas[0], datas[5],bOverSave);
                        }
                    }
                }
            }
            mRepository.syncParamValue();
            mLog.error("---------------end---------------------");
            reader.close();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * 利用第三方开源包cpdetector获取文件编码格式
     *
     * @param path 要判断文件编码格式的源文件的路径
     * @author huanglei
     * @version 2012-7-12 14:05
     */
    private static String getFileEncode(String path) {
        /*
         * detector是探测器，它把探测任务交给具体的探测实现类的实例完成。
         * cpDetector内置了一些常用的探测实现类，这些探测实现类的实例可以通过add方法 加进来，如ParsingDetector、
         * JChardetFacade、ASCIIDetector、UnicodeDetector。
         * detector按照“谁最先返回非空的探测结果，就以该结果为准”的原则返回探测到的
         * 字符集编码。使用需要用到三个第三方JAR包：antlr.jar、chardet.jar和cpdetector.jar
         * cpDetector是基于统计学原理的，不保证完全正确。
         */
        CodepageDetectorProxy detector = CodepageDetectorProxy.getInstance();
        /*
         * ParsingDetector可用于检查HTML、XML等文件或字符流的编码,构造方法中的参数用于
         * 指示是否显示探测过程的详细信息，为false不显示。
         */
        detector.add(new ParsingDetector(false));
        /*
         * JChardetFacade封装了由Mozilla组织提供的JChardet，它可以完成大多数文件的编码
         * 测定。所以，一般有了这个探测器就可满足大多数项目的要求，如果你还不放心，可以
         * 再多加几个探测器，比如下面的ASCIIDetector、UnicodeDetector等。
         */
        detector.add(JChardetFacade.getInstance());// 用到antlr.jar、chardet.jar
        // ASCIIDetector用于ASCII编码测定
        detector.add(ASCIIDetector.getInstance());
        // UnicodeDetector用于Unicode家族编码的测定
        detector.add(UnicodeDetector.getInstance());
        java.nio.charset.Charset charset = null;
        File f = new File(path);
        try {
            charset = detector.detectCodepage(f.toURI().toURL());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        if (charset != null) {
            return charset.name();
        }
        else {
            return null;
        }
    }

}


